package com.tianji.learning.service.impl;

import com.tianji.api.client.user.UserClient;
import com.tianji.api.dto.user.UserDTO;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.StringUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.constants.RedisConstants;
import com.tianji.learning.domain.po.PointsBoard;
import com.tianji.learning.domain.query.PointsBoardQuery;
import com.tianji.learning.domain.vo.PointsBoardItemVO;
import com.tianji.learning.domain.vo.PointsBoardVO;
import com.tianji.learning.mapper.PointsBoardMapper;
import com.tianji.learning.service.IPointsBoardService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import static com.tianji.learning.constants.LearningConstants.POINTS_BOARD_TABLE_PREFIX;

/**
 * <p>
 * 学霸天梯榜 服务实现类
 * </p>
 *
 * @author liuchun
 * @since 2024-09-07
 */
@Service
public class PointsBoardServiceImpl extends ServiceImpl<PointsBoardMapper, PointsBoard> implements IPointsBoardService {


    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private UserClient userClient;

    /**
     * 查询指定赛季的积分排行榜以及当前用户的积分和排名信息
     * @param query
     * @return
     */
    @Override
    public PointsBoardVO getPointsBoard(PointsBoardQuery query) {
        //获取当前登录用户Id
        Long userId = UserContext.getUser();
        LocalDate now = LocalDate.now();
        String format = now.format(DateTimeFormatter.ofPattern("yyyyMM"));
        String key = RedisConstants.POINTS_BOARD_KEY_PREFIX + format;
        //判断是否当前赛季还是历史赛季 赛季Id为null 或者0 代表当前赛季
        Boolean isCurrentSeason = query.getSeason() == null || query.getSeason() == 0;
        //查询我的排名和积分 注意走Redis还是DB
        PointsBoard board = null;
        if (isCurrentSeason) {
            //当前赛季，走Redis
            board = queryMyCurrentRankByRedis(key,userId.toString());
        }else {
            //历史赛季，走DB
             board = queryMyHistoryRankByDB(query.getSeason(),userId.toString());
        }
        //分页查询赛季列表 根据赛季Id判断走Redis还是DB
        List<PointsBoardItemVO> pointsBoardItemVOList = isCurrentSeason ? queryCurrentRankByRedis(key,query.getPageNo(),query.getPageSize()) : queryHistoryRankByDB(query);
        //封装vo返回
        PointsBoardVO vo = new PointsBoardVO();
        vo.setRank(board.getRank());
        vo.setPoints(board.getPoints());
        vo.setBoardList(pointsBoardItemVOList);
        return vo;
    }

    //创建数据库表
    @Override
    public void createPointsBoardTableBySeason(Integer season) {
        getBaseMapper().createPointsBoardTable(POINTS_BOARD_TABLE_PREFIX + season);
    }

    //在数据库中查询历史赛季排行
    private List<PointsBoardItemVO> queryHistoryRankByDB(PointsBoardQuery query) {
        //todo
        return null;
    }

    //在Redis中查询排名和积分
    public List<PointsBoardItemVO> queryCurrentRankByRedis(String key, Integer pageNo, Integer pageSize) {
        log.debug("开始查询......");
        int start = (pageNo - 1) * pageSize;
        int end = start + pageSize - 1;
        Set<ZSetOperations.TypedTuple<String>> tuples = redisTemplate.opsForZSet().reverseRangeWithScores(key, start, end);
        if (CollUtils.isEmpty(tuples)) {
            return CollUtils.emptyList();
        }
        List<Long> list = tuples.stream().map(tuple -> Long.valueOf(tuple.getValue())).collect(Collectors.toList());
        List<UserDTO> userDTOS = userClient.queryUserByIds(list);
        if (CollUtils.isEmpty(userDTOS)) {
            throw new BizIllegalException("用户不存在");
        }
        List<PointsBoardItemVO> vos = new ArrayList<>();
        Map<Long, UserDTO> userDTOMap = userDTOS.stream().collect(Collectors.toMap(UserDTO::getId, c -> c));
        int rank = start + 1;
        for(ZSetOperations.TypedTuple<String> tuple : tuples){
            String value = tuple.getValue();//用户Id
            Double score = tuple.getScore();//分值
            if (StringUtils.isBlank(value) || score == null) {
                continue;
            }
            PointsBoardItemVO vo = new PointsBoardItemVO();
            vo.setRank(rank++);
            vo.setPoints(score.intValue());
            vo.setName(userDTOMap.get(Long.valueOf(value)).getName());

            vos.add(vo);
        }
        log.debug("查询完成......");
        return vos;
    }

    //在数据库中查询我的排名和积分
    private PointsBoard queryMyHistoryRankByDB(Long season, String userId) {
        //todo
        return null;
    }

    //查询当前赛季我的排名和积分
    private PointsBoard queryMyCurrentRankByRedis(String key,String userId) {
        Double score = redisTemplate.opsForZSet().score(key, userId);
        Long rank = redisTemplate.opsForZSet().reverseRank(key, userId);
        PointsBoard board = new PointsBoard();
        board.setPoints(score == null ? 0 : score.intValue());
        board.setRank(rank == null ? 0 : rank.intValue() + 1);
        return board;
    }
}
